\ProvidesPackage{kaobiblio}

%----------------------------------------------------------------------------------------
%	PACKAGE OPTIONS AND DEPENDENCIES
%----------------------------------------------------------------------------------------

\RequirePackage{etoolbox} % Easy programming to modify TeX stuff
\RequirePackage{perpage} % Reset counters
\RequirePackage{iflang} % Check the document language
\RequirePackage{xparse} % Parse arguments for macros
\RequirePackage{xstring} % Parse strings
\RequirePackage{hyperref} % Required for hyperlinks
\RequirePackage{kvoptions} % Handle package options

% Set up the package options
\SetupKeyvalOptions{
	family = kaobiblio,
	prefix = kaobiblio@
}

\DeclareBoolOption{addspace}% If true, automatically add a space before printing the citation marker
\DeclareBoolOption{linkeverything}% If true, the author name is a hyperlink in citation styles that support it

% Choose the default options, which will be overwritten by the options 
% passed to this package.
\PassOptionsToPackage{
	%style=numeric-comp,
	%citestyle=authortitle-icomp,
	citestyle=numeric-comp,
	%bibstyle=authoryear,
	bibstyle=numeric,
	sorting=none,
	%sorting=nyt,
	%sortcites=true,
	%autocite=footnote,
	backend=biber, % Compile the bibliography with biber
	hyperref=true,
	backref=true,
	citecounter=true,
	pagetracker=true,
	citetracker=true,
	ibidtracker=context,
	autopunct=true,
	autocite=plain,
}{biblatex}

% Pass the unknown options to biblatex, overwriting the previous settings. Avoid passing the kao-specific options.
\DeclareDefaultOption{%
	\IfBeginWith{\CurrentOption}{addspace}{}{%
	\IfBeginWith{\CurrentOption}{linkeverything}{}{%
		\PassOptionsToPackage{\CurrentOption}{biblatex}%
	}}%
}

% Process the options
\ProcessKeyvalOptions{kaobiblio}

% Load biblatex
\RequirePackage{biblatex}

% Remove some unwanted entries from the bibliography
\AtEveryBibitem{
	\clearfield{issn}
	\clearfield{isbn}
	\clearfield{archivePrefix}
	\clearfield{arxivId}
	\clearfield{pmid}
	\clearfield{eprint}
	\ifentrytype{online}{}{\ifentrytype{misc}{}{\clearfield{url}}}
	\ifentrytype{book}{\clearfield{doi}}{}
}

% Convert months to integers
\DeclareSourcemap{
	\maps[datatype=bibtex]{
		\map[overwrite]{
			\step[fieldsource=month, match={jan}, replace=${1}]
			\step[fieldsource=month, match={feb}, replace=${2}]
			\step[fieldsource=month, match={mar}, replace=${3}]
			\step[fieldsource=month, match={apr}, replace=${4}]
			\step[fieldsource=month, match={may}, replace=${5}]
			\step[fieldsource=month, match={jun}, replace=${6}]
			\step[fieldsource=month, match={jul}, replace=${7}]
			\step[fieldsource=month, match={aug}, replace=${8}]
			\step[fieldsource=month, match={sep}, replace=${9}]
			\step[fieldsource=month, match={oct}, replace=${10}]
			\step[fieldsource=month, match={nov}, replace=${11}]
			\step[fieldsource=month, match={dec}, replace=${12}]
		}
	}
}

%----------------------------------------------------------------------------------------
%	BACK REFERENCES
%----------------------------------------------------------------------------------------

% Check if a string is in a comma-separated list
\newcommand\IfStringInList[2]{\IfSubStr{,#2,}{,#1,}}

% Set the language-specific back reference strings
% #LANGUAGE
\@ifpackageloaded{polyglossia}{%
	\IfLanguageName{danish}{%
		\DefineBibliographyStrings{danish}{%
			backrefpage = {citeret på side},
			backrefpages = {citeret på sider},
		}
	}{}
	\IfLanguageName{english}{%
		\DefineBibliographyStrings{english}{%
			backrefpage = {cited on page},
			backrefpages = {cited on pages},
		}
	}{}
	\IfLanguageName{italian}{%
		\DefineBibliographyStrings{italian}{%
			backrefpage = {citato a pag.},
			backrefpages = {citato a pagg.},
		}
	}{}
}{
	\@ifpackageloaded{babel}{%
		\IfStringInList{danish}{\bbl@loaded}{%
			\DefineBibliographyStrings{danish}{%
				backrefpage = {citeret på side},
				backrefpages = {citeret på sider},
			}
		}{}
		\IfStringInList{english}{\bbl@loaded}{%
			\DefineBibliographyStrings{english}{%
				backrefpage = {cited on page},
				backrefpages = {cited on pages},
			}
		}{}
		\IfStringInList{italian}{\bbl@loaded}{%
			\DefineBibliographyStrings{italian}{%
				backrefpage = {citato a pag.},
				backrefpages = {citato a pagg.},
			}
		}{}
	}{}
}

%----------------------------------------------------------------------------------------
%	CITATION COMMANDS
%----------------------------------------------------------------------------------------

% Command to format the marginnote created for cited items
\NewDocumentCommand{\formatmargincitation}{m}{% The parameter is a single citation key
	\parencite{#1}: \citeauthor*{#1} (\iffieldundef{year}{\bibsstring{nodate}}{\printfield{year}}), \citefield{#1}[emph]{title}%
}

% Command to format the marginnote created for supercited items
\NewDocumentCommand{\formatmarginsupercitation}{m}{% The parameter is a single citation key
	\supercite{#1} \citeauthor*{#1} (\iffieldundef{year}{\bibsstring{nodate}}{\printfield{year}})%
}

% The following command needs to be redefined every time \sidecite is called in order for \DeclareCiteCommand's wrapper to work correctly
\NewDocumentCommand{\kaobiblio@marginnote}{m}{%
	\marginnote{#1}%
}

% biblatex-like commands that also print a citation in the margin
% Usage:
	% First optional argument is always vertical shift and must be given as an (empty) argument when using following a postnote and/or prenote
	% Second optional argument is always the postnote if the third argument isn't specified or is the prenote if the third argument is specified (same pattern as the biblatex commands)
	% Third optional argument is always the postnote
	% Mandatory argument is always the citation key(s)

% Command to \cite and print a citation in the margin
% First optional argument: vertical shift
% Second optional argument: postnote if the third argument isn't specified; prenote if the third argument is specified (same pattern as the \textcite command)
% Third optional argument: postnote
% Mandatory argument: citation key
\NewDocumentCommand{\sidecite}{o o o m}{%
	\RenewDocumentCommand{\kaobiblio@marginnote}{m}{%
		\marginnote[#1]{##1}%
	}%
	\DeclareCiteCommand{\kaobiblio@sidecite}[\kaobiblio@marginnote]{%
	}{%
		\formatmargincitation{\thefield{entrykey}}%
	}{%
		\\% separator between multiple citations
	}{%
	}%
	% With this we print the marker in the text and add the item to the bibliography at the end
	\IfNoValueOrEmptyTF{#2}%
	{\def\@tempa{\cite{#4}\kaobiblio@sidecite{#4}}}%
	{\IfNoValueOrEmptyTF{#3}%
		{\IfNoValueTF{#3}%
			{\def\@tempa{\cite[#2]{#4}\kaobiblio@sidecite{#4}}}%
			{\def\@tempa{\cite[#2][]{#4}\kaobiblio@sidecite{#4}}}% postnote is empty, so pass empty postnote
		}%
		{\def\@tempa{\cite[#2][#3]{#4}\kaobiblio@sidecite{#4}}}%
	}%
	\ifkaobiblio@addspace%
		\unskip~\@tempa%
	\else%
		\@tempa%
	\fi%
}

% Command to \supercite and print a citation in the margin
% First optional argument: vertical shift
% Second optional argument: postnote if the third argument isn't specified; prenote if the third argument is specified (same pattern as the \textcite command)
% Third optional argument: postnote
% Mandatory argument: citation key
\NewDocumentCommand{\sidesupercite}{o o o m}{%
	\RenewDocumentCommand{\kaobiblio@marginnote}{m}{%
		\marginnote[#1]{##1}%
	}%
	\DeclareCiteCommand{\kaobiblio@sidesupercite}[\kaobiblio@marginnote]{%
	}{%
		\formatmarginsupercitation{\thefield{entrykey}}%
	}{%
		\\% separator between multiple citations
	}{%
	}%
	% With this we print the marker in the text and add the item to the bibliography at the end
	\IfNoValueOrEmptyTF{#2}%
	{\def\@tempa{\supercite{#4}\kaobiblio@sidesupercite{#4}}}%
	{\IfNoValueOrEmptyTF{#3}%
		{\IfNoValueTF{#3}%
			{\def\@tempa{\supercite[#2]{#4}\kaobiblio@sidesupercite{#4}}}%
			{\def\@tempa{\supercite[#2][]{#4}\kaobook@sidesupercite{#4}}}% postnote is empty, so pass empty postnote
		}%
		{\def\@tempa{\supercite[#2][#3]{#4}\kaobiblio@sidesupercite{#4}}}%
	}%
	\@tempa%
}

% Command to \textcite and print a citation in the margin
% First optional argument: vertical shift
% Second optional argument: postnote if the third argument isn't specified; prenote if the third argument is specified (same pattern as the \textcite command)
% Third optional argument: postnote
% Mandatory argument: citation key
\NewDocumentCommand{\sidetextcite}{o o o m}{%
	\RenewDocumentCommand{\kaobiblio@marginnote}{m}{%
		\marginnote[#1]{##1}%
	}%
	\DeclareCiteCommand{\kaobiblio@sidecite}[\kaobiblio@marginnote]{%
	}{%
		\formatmargincitation{\thefield{entrykey}}%
	}{%
		\\% separator between multiple citations
	}{%
	}%
	% With this we print the marker in the text and add the item to the bibliography at the end
	\IfNoValueOrEmptyTF{#2}%
		{\def\@tempa{\textcite{#4}\kaobiblio@sidecite{#4}}}%
		{\IfNoValueOrEmptyTF{#3}%
			{\IfNoValueTF{#3}%
				{\def\@tempa{\textcite[#2]{#4}\kaobiblio@sidecite{#4}}}%
				{\def\@tempa{\textcite[#2][]{#4}\kaobook@sidecite{#4}}}% postnote is empty, so pass empty postnote
			}%
			{\def\@tempa{\textcite[#2][#3]{#4}\kaobiblio@sidecite{#4}}}%
		}%
	\ifkaobiblio@addspace%
		\unskip~\@tempa%
	\else%
		\@tempa%
	\fi%
}

% Command to \parencite or \parencite* and print a citation in the margin
% First optional (star) argument: use \parencite* if included; otherwise use \parencite
% Second optional argument: vertical shift
% Third optional argument: postnote if the fourth argument isn't specified; prenote if the fourth argument is specified (same pattern as the \parencite command)
% Fourth optional argument: postnote
% Mandatory argument: citation key
\NewDocumentCommand{\sideparencite}{s o o o m}{%
	\RenewDocumentCommand{\kaobiblio@marginnote}{m}{%
		\marginnote[#2]{##1}%
	}%
	\DeclareCiteCommand{\kaobiblio@sidecite}[\kaobiblio@marginnote]{%
	}{%
		\formatmargincitation{\thefield{entrykey}}%
	}{%
		\\% separator between multiple citations
	}{%
	}%
	% With this we print the marker in the text and add the item to the bibliography at the end
	\IfBooleanTF#1%
		{\IfNoValueOrEmptyTF{#3}%
			{\parencite*{#5}\kaobiblio@sidecite{#5}}%
			{\IfNoValueOrEmptyTF{#4}%
				{\IfNoValueTF{#4}%
					{\def\@tempa{\parencite*[#3]{#5}\kaobiblio@sidecite{#5}}}%
					{\def\@tempa{\parencite*[#3][]{#5}\kaobiblio@sidecite{#5}}}% postnote is empty, so pass empty postnote
				}%
				{\def\@tempa{\parencite*[#3][#4]{#5}\kaobiblio@sidecite{#5}}}%
			}%
		}%
		{\IfNoValueOrEmptyTF{#3}%
			{\def\@tempa{\parencite{#5}\kaobiblio@sidecite{#5}}}%
			{\IfNoValueOrEmptyTF{#4}%
				{\IfNoValueTF{#4}%
					{\def\@tempa{\parencite[#3]{#5}\kaobiblio@sidecite{#5}}}%
					{\def\@tempa{\parencite[#3][]{#5}\kaobiblio@sidecite{#5}}}% postnote is empty, so pass empty postnote
				}%
				{\def\@tempa{\parencite[#3][#4]{#5}\kaobiblio@sidecite{#5}}}%
			}%
		}%
	\ifkaobiblio@addspace%
		\unskip~\@tempa%
	\else%
		\@tempa%
	\fi%
}


%----------------------------------------------------------------------------------------
%	LINKING THE AUTHOR'S NAME
%----------------------------------------------------------------------------------------

% In biblatex, when citing with the style authoryear or using \textcite, only the year is linked to the reference in the bibliography. Despite the arguments of one of the mantainers of the biblatex package (https://github.com/plk/biblatex/issues/428), some users think that in the author* style the author name should be a link as well. The `linkeverything' option provides an easy way to activate this behaviour.

\ifkaobiblio@linkeverything
	\xpatchbibmacro{cite}
		{\usebibmacro{cite:label}%
		 \setunit{\printdelim{nonameyeardelim}}%
		 \usebibmacro{cite:labeldate+extradate}}
		{\printtext[bibhyperref]{%
			 \DeclareFieldAlias{bibhyperref}{default}%
			 \usebibmacro{cite:label}%
			 \setunit{\printdelim{nonameyeardelim}}%
			 \usebibmacro{cite:labeldate+extradate}}}
		{}
		{\PackageWarning{biblatex-patch}
			 {Failed to patch cite bibmacro}}

	% Include labelname in labelyear link
	\xpatchbibmacro{cite}
		{\printnames{labelname}%
		 \setunit{\printdelim{nameyeardelim}}%
		 \usebibmacro{cite:labeldate+extradate}}
		{\printtext[bibhyperref]{%
			 \DeclareFieldAlias{bibhyperref}{default}%
			 \printnames{labelname}%
			 \setunit{\printdelim{nameyeardelim}}%
			 \usebibmacro{cite:labeldate+extradate}}}
		{}
		{\PackageWarning{biblatex-patch}
			 {Failed to patch cite bibmacro}}

	% Access hyperref's citation link start/end commands
	\makeatletter
	\protected\def\blx@imc@biblinkstart{%
		\@ifnextchar[%]
			{\blx@biblinkstart}
			{\blx@biblinkstart[\abx@field@entrykey]}}
	\def\blx@biblinkstart[#1]{%
		\blx@sfsave\hyper@natlinkstart{\the\c@refsection @#1}\blx@sfrest}
	\protected\def\blx@imc@biblinkend{%
		\blx@sfsave\hyper@natlinkend\blx@sfrest}
	\blx@regimcs{\biblinkstart \biblinkend}
	\makeatother

	\newbool{cbx:link}

	% Include parentheses around labelyear in \textcite only in
	% single citations without pre- and postnotes
	\def\iflinkparens{%
		\ifboolexpr{ test {\ifnumequal{\value{multicitetotal}}{0}} and
					 test {\ifnumequal{\value{citetotal}}{1}} and
					 test {\iffieldundef{prenote}} and
					 test {\iffieldundef{postnote}} }}

	\xpatchbibmacro{textcite}
		{\printnames{labelname}}
		{\iflinkparens
			 {\DeclareFieldAlias{bibhyperref}{default}%
				\global\booltrue{cbx:link}\biblinkstart%
				\printnames{labelname}}
			 {\printtext[bibhyperref]{\printnames{labelname}}}}
		{}
		{\PackageWarning{biblatex-patch}
			 {Failed to patch textcite bibmacro}}

	\xpatchbibmacro{textcite}
		{\usebibmacro{cite:label}}
		{\iflinkparens
			 {\DeclareFieldAlias{bibhyperref}{default}%
				\global\booltrue{cbx:link}\biblinkstart%
				\usebibmacro{cite:label}}
			 {\usebibmacro{cite:label}}}
		{}
		{\PackageWarning{biblatex-patch}
			 {Failed to patch textcite bibmacro}}

	\xpretobibmacro{textcite:postnote}
		{\ifbool{cbx:link}
			 {\ifbool{cbx:parens}
					{\bibcloseparen\global\boolfalse{cbx:parens}}
					{}%
				\biblinkend\global\boolfalse{cbx:link}}
			 {}}
		{}
		{\PackageWarning{biblatex-patch}
			 {Failed to patch textcite:postnote bibmacro}}
\else
\fi

%----------------------------------------------------------------------------------------
%	CITATION ENVIRONMENTS
%----------------------------------------------------------------------------------------

% TODO: create a fancy environment for this. Perhaps printing also the 
% abstract.

% Cite commands (assuming biblatex is loaded)
\DeclareCiteCommand{\fullcite}{%
	\defcounter{maxnames}{99}%
	\usebibmacro{prenote}}
	{\clearfield{url}%
	\clearfield{pages}%
	\clearfield{pagetotal}%
	\clearfield{edition}%
	\clearfield{issn}%
	\clearfield{doi}%
	\usedriver
	{\DeclareNameAlias{sortname}{default}}
	{\thefield{entrytype}}
}
{\multicitedelim}
{\usebibmacro{postnote}}
